package com.ecric.http.http;

import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 *
 * 文件下载工具类：多线程下载
 * <h3>Description</h3>
 * TODO
 * <h3>Author</h3> Eric
 * <h3>Date</h3> 2017/9/18 17:55
 * <h3>Copyright</h3> Copyright (c)2017 Shenzhen TLKY  Co., Ltd. Inc. All rights reserved.
 */
public class FileDownUtil {
    /**资源路径*/
    private String path;
    /**下载文件保存的位置*/
    private String targetFile;
    private int threadNum;
    /**定义下载的线程对象*/
    private DownThread[] threads;
    /**定义下载的文件的总大小*/
    private int fileSize;
    private static FileDownUtil fildownUtil = null;
    /**已经下载的文件总大小*/
    private int sumSize = 0;
    private DownloadProgressListener downloadProgressListener;

    private FileDownUtil(String path,String targetFile,int threadNum) {
        this.path = path;
        this.targetFile = targetFile;
        this.threadNum = threadNum;
        this.threads = new DownThread[threadNum];
    }

    /**
     * 单例模式
     * (此处输入方法执行任务.)
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2017/9/19,10:33
     * <h3>UpdateTime</h3> 2017/9/19,10:33
     * <h3>CreateAuthor</h3> Eric
     * <h3>UpdateAuthor</h3>
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     * @param path
     * @param targetFile
     * @param threadNum
     * @return
     */
    public static synchronized FileDownUtil getInstance(String path,String targetFile,int threadNum) {
        if (fildownUtil == null){
            fildownUtil = new FileDownUtil(path,targetFile,threadNum);
        }
        return fildownUtil;
    }


    /**
     * 开始下载文件
     *
     */
    public void download(){
        try {
            URL url = new URL(path);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(5000);
            connection.setRequestMethod("GET");
//            connection.setDoInput(true);
            connection.setRequestProperty("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, " +
                    "application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, " +
                    "application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, " +
                    "application/vnd.ms-powerpoint, application/msword,text/xml , text/html ,application/json ,*/*");
            connection.setRequestProperty("Accept-Language","zh-CN");
//            connection.setRequestProperty("Accept-Charset","UTF-8");
            connection.setRequestProperty("Connection","Keep-Alive");
//            connection.setRequestProperty("Referer", path);// 先前网页的地址，当前请求网页紧随其后,即来路
            connection.setRequestProperty("Charset", "UTF-8");
//            connection.connect();
            if (connection.getResponseCode() == 200){
                //得到文件大小
                fileSize = connection.getContentLength();
            }else {
                Log.e("FileDownUtil======>","网络异常");
                return;
            }
            connection.disconnect();
            int currentPartSize = fileSize % threadNum == 0 ? fileSize / threadNum : fileSize / threadNum + 1;
            RandomAccessFile file = new RandomAccessFile(targetFile,"rw");
            //设置本地文件的大小
            file.setLength(fileSize);
            file.close();
            for (int i = 0; i < threadNum; i++) {
                //计算每条线程的下载开始位置
                int startPos = i * currentPartSize;
                //每个线程使用一个RandomAccessFile进行下载
                RandomAccessFile currentPart = new RandomAccessFile(targetFile,"rwd");
                //定位该线程的下载位置
                currentPart.seek(startPos);
                //创建下载线程
                threads[i] = new DownThread(startPos,currentPartSize,currentPart);
                //开始下载
                threads[i].start();
            }

            //文件是否下载完成 false 下载完成 否则为下载完成
            boolean isNotComplete = true;
            /*已经下载的文件的长度*/
            int downloadLength = 0 ;
            while (isNotComplete){
                downloadLength = 0;
                Thread.sleep(500);
                isNotComplete = false;//假定全部线程下载完成
                for (int i = 0; i < threads.length; i++) {
                    if (this.threads[i] != null && !this.threads[i].isFinish()) {//如果发现线程未完成下载
                        isNotComplete = true;
                        if (this.threads[i].getLength() == -1) {//如果下载失败,再重新下载
                            //计算每条线程的下载开始位置
                            int startPos = i * currentPartSize;
                            //每个线程使用一个RandomAccessFile进行下载
                            RandomAccessFile currentPart = new RandomAccessFile(targetFile,"rwd");
                            //定位该线程的下载位置
                            currentPart.seek(startPos);
                            //创建下载线程
                            threads[i] = new DownThread(startPos,currentPartSize,currentPart);
                            this.threads[i].setPriority(7);
                            this.threads[i].start();
                        }
                    }
                    //计算已下载文件的大小
                    if (this.threads[i] != null && this.threads[i].getLength() != -1){
                        downloadLength += this.threads[i].getLength();
                    }
                }
                if (downloadProgressListener != null){
                    downloadProgressListener.onDownloadSize(downloadLength,fileSize);
                }
            }
            //走到这里证明文件已经下载完成 那么已经下载的大小就是文件的大小
            if (downloadProgressListener != null){
                downloadProgressListener.onDownloadSize(fileSize,fileSize);
            }
        } catch (MalformedURLException e) {
            Log.e("download=======>",e.getMessage());
        } catch (IOException e) {
            Log.e("download=======>",e.getMessage());
        }catch (InterruptedException e) {
//                    e.printStackTrace();
            Log.e("download=======>",e.getMessage());

        }

    }


    /**
     *
     * @return 返回下载的完成百分比
     */
    public double getCompleteRate(){
        int sumSize = 0;
        for (int i = 0; i < threadNum; i++) {
            sumSize += threads[i].length;
        }
        return sumSize * 1.0 / fileSize;
    }


    private class DownThread extends Thread{
        /**当前线程的下载位置*/
        private int startPos;
        /**定义当前线程负责下载的文件大小*/
        private  int currentPartSize;
        /**当前线程需要下载的文件夹*/
        private RandomAccessFile currentPart;
        /**定义该线程已下载的字节数 默认 -1 */
        public int  length = -1 ;
        /** 当前线程的下载任务是否完成 true 下载完成 否则为下载完成 */
        public boolean isFinish = false;

        public DownThread(int startPos, int currentPartSize, RandomAccessFile currentPart) {
            this.startPos = startPos;
            this.currentPartSize = currentPartSize;
            this.currentPart = currentPart;
        }

        @Override
        public void run() {
            super.run();
            try {
                URL url = new URL(path);
                HttpURLConnection connection  = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(5000);
                connection.setRequestMethod("GET");
//                connection.setDoInput(true);
                connection.setRequestProperty("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, " +
                    "application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, " +
                    "application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, " +
                    "application/vnd.ms-powerpoint, application/msword,text/xml , text/html ,application/json ,*/*");
                connection.setRequestProperty("Accept-Language","zh-CN");
                connection.setRequestProperty("Accept-Charset","UTF-8");
                connection.setRequestProperty("Connection","Keep-Alive");
                connection.setRequestProperty(
                        "User-Agent",
                        "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; " +
                                ".NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30;" +
                                " .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
//                connection.setRequestProperty("Range", "bytes=" + startPos + "-" + (startPos + currentPartSize));//设置获取实体数据的范围
//                connection.setRequestProperty("Referer", path);// 先前网页的地址，当前请求网页紧随其后,即来路
                connection.setRequestProperty("Charset", "UTF-8");
                InputStream is = connection.getInputStream();
                //跳过startPos个字节，表明该线程只下载自己负责哪部分文件
                is.skip(this.startPos);
                byte[] buffer = new byte[1024];
                int hasRead = 0;
                //读取网络数据，并写入本地文件
                while (length < currentPartSize && (hasRead = is.read(buffer)) > 0){
                    currentPart.write(buffer,0 ,hasRead);
                    //累计该线程下载的总大小
                    length += hasRead;
                }
                currentPart.close();
                is.close();
                isFinish = true;
            } catch (MalformedURLException e) {
                length = -1;//下载失败
                Log.e("DownThread=======>",e.getMessage());
            } catch (IOException e) {
                Log.e("DownThread=======>",e.getMessage());
                length = -1;//下载失败
            }
        }


        /**
         * 判断是否已经下载完
         *
         * @return
         */
        public boolean isFinish() {
            return isFinish;
        }

        /**
         * 获取已经下载的长度
         * @return
         */
        public int getLength() {
            return length;
        }
    }

    /**
     *  下载进度监听
     */
    public interface DownloadProgressListener {
        /**
         * @param downloadSize 已经下载的文件的大小
         * @param fileSize 文件总的大小
         */
         void onDownloadSize(int downloadSize,int fileSize);
    }

    /**
     * 设置下载进度监听
     * @param lintener
     */
    public void setOnDownloadProgressListener(DownloadProgressListener lintener){
        downloadProgressListener = lintener;
    }


}
